﻿using System;
using System.Collections.Generic;
using System.Text;
using Barbar.MapReport.Common.Drawing.Commands;
using Barbar.MapReport.Common;
using Barbar.MapReport.Common.Drawing;
using JsonSharp.Collections;
using JsonSharp.Values;
using Barbar.MapReport.HtmlRender.Shapes;
using System.Globalization;

namespace Barbar.MapReport.HtmlRender.Operations {
  internal class AddValueIndicatorsOperation : RenderBaseOperation {
    private AddValueIndicatorsCommand m_Command;
    private int MinimalRadius = 2;

    public AddValueIndicatorsOperation(AddValueIndicatorsCommand command) {
      if (command == null)
        throw new ArgumentNullException("command");
      m_Command = command;
    }

    #region RenderBaseOperation Members

    private void GetMaxMin(out decimal min, out decimal max) {
      min = ((IBusinessValue)m_Command.Points[0]).Value;
      max = min;
      foreach (IBusinessValue value in m_Command.Points) {
        if (max < value.Value)
          max = value.Value;
        if (min > value.Value)
          min = value.Value;
      }
    }

    protected override void RenderInternal(RenderingContext context) {
      if (m_Command.Points.Count == 0)
        return;

      decimal min, max;
      GetMaxMin(out min, out max);

      foreach (BusinessGeoPoint point in m_Command.Points) {
        JsonObjects circle = new JsonObjects();

        int radius = GetRadius(point, min, max);
        string shapeUrl = GetShapeUrl(radius, context.MapProxyUrl);

        circle.Add(new JsonStringValue("url"), new JsonStringValue(shapeUrl));
        circle.Add(new JsonStringValue("width"), new JsonNumberValue(radius * 2));
        circle.Add(new JsonStringValue("height"), new JsonNumberValue(radius * 2));
        circle.Add(new JsonStringValue("lat"), new JsonNumberValue(point.Latitude));
        circle.Add(new JsonStringValue("lng"), new JsonNumberValue(point.Longitude));
        if (m_Command.BubbleBehavior != null) {
          circle.Add(new JsonStringValue("description"), new JsonStringValue(GetDescription(point, m_Command.BubbleBehavior)));
          circle.Add(new JsonStringValue("showBubbleOnMouseOver"), new JsonBoolValue(m_Command.BubbleBehavior.ShowOnMouseOver));
        }

        if (m_Command.RedirectBehavior != null) {
          circle.Add(new JsonStringValue("hyperlink"), new JsonStringValue(GetHyperlink(point, m_Command.RedirectBehavior)));
        }

        context.Write(JavaScriptFunction.CreateMapMarker, circle);
      }
    }

    private static string GetDescription(BusinessGeoPoint point, MarkerBubbleBehavior markerBubbleBehavior) {
      if (String.IsNullOrEmpty(markerBubbleBehavior.DescriptionTemplate))
        return null;
      string result = markerBubbleBehavior.DescriptionTemplate;
      result = result.Replace("{Value}", Convert.ToString(point.Value1, CultureInfo.InvariantCulture));

      if (!String.IsNullOrEmpty(point.Name))
        result = result.Replace("{Name}", point.Name);
      return result;
    }

    private static string GetHyperlink(BusinessGeoPoint point, MarkerRedirectBehavior markerRedirectBehavior) {
      if (String.IsNullOrEmpty(markerRedirectBehavior.NavigateUrl))
        return null;

      string hyperlink = markerRedirectBehavior.NavigateUrl;
      return hyperlink.Replace("{Value}", Convert.ToString(point.Value1, CultureInfo.InvariantCulture));
    }

    private string GetShapeUrl(int radius, string mapProxyUrl) {
      IShape shape = new CircleShape(radius, m_Command.Color.Color);
      return ShapeHandler.GetURL(shape).ToString(mapProxyUrl);
    }

    private int GetRadius(BusinessGeoPoint point, decimal min, decimal max) {
      int radius;
      if (max == min)
        radius = m_Command.MinSize;
      else
        radius = (int)(((point.Value1 - min) * (m_Command.MaxSize - m_Command.MinSize)) / (max - min)) + m_Command.MinSize;
      
      if (radius < MinimalRadius)
        radius = MinimalRadius;

      return radius;
    }

    #endregion
  }
}
